#include<iostream>
#include<string>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include<cstring>
const int gCreater=1;
const int gUser=2;
const std::string gpathname="/home/whb/code/111/code/lesson22/4.shm";
const int gproj_id=0x66;
const int gShmSize=4097;//4096*n
class Shm
{
    private:
        key_t GetCommKey()
        {
            key_t k=ftok(_pathname.c_str(),_proj_id);
            if(k<0)
            {
                perror("ftok");
            }
            return k;
        }
        int GetShmHelper(key_t key,int size, int flag)
        {
            int shmid =shmget(key,size,flag);
            if(shmid<0)
            {

                perror("shmget");
            }
            return shmid;
        }
    public:
        Shm(const std::string &pathname,int proj_id,int who)
            :_pathname(pathname),_proj_id(proj_id),_who(who),_addrshm(nullptr)
        {
            _key=GetCommKey();
            if(_who==gCreater)
                GetShmUserCreate();
            else if(_who==gUser)
                CreatShmForUse();
            std::cout << "shmid: " << _shmid << std::endl;
            std::cout << "_key: " << ToHex(_key) << std::endl;
        }
        ~Shm()
        {
            if(_who==gCreater)
            {
                int res=shmctl(_shmid,IPC_RMID,nullptr);
            }
            std::cout<<"shm remove done..."<<std::endl;
        }
        std::string ToHex(key_t key)
        {
            char buffer[128];
            snprintf(buffer,sizeof(buffer),"0x%x",key);
            return buffer;
        }
        bool GetShmUserCreate()
        {
            if(_who==gCreater)
            {
                _shmid=GetShmHelper(_key,gShmSize,IPC_CREAT|IPC_EXCL|0666);
                if(_shmid>=0)
                {
                    return true;
                }
                std::cout<<"shm creat done..."<<std::endl;//这里的意思是已经创建完了
            }
            return false;
        }
        bool CreatShmForUse()
        {
            if(_who==gUser)
            {
                _shmid=GetShmHelper(_key,gShmSize,IPC_CREAT|0666);
                if(_shmid>=0)
                {
                    return true;
                }
                std::cout << "shm get done..." << std::endl;
            }
            return false;

        }
        void *AttachShm()
        {
            void *shmaddr=shmat(_shmid,NULL,0);
            if(shmaddr==nullptr)
            {
                perror("shmat");
            }
            return shmaddr;
            

        }
        void DetachShm(void * shmaddr)
        {
            if(shmaddr==nullptr)    return ;
            shmdt(shmaddr);            
        }
        void Zero()
        {
            if(_addrshm)
            {
                memset(_addrshm,0,gShmSize);
            }
        }
        void DebugShm()
        {
            struct shmid_ds ds;
            int n =shmctl(_shmid,IPC_STAT,&ds);
            if(n<0)return;
            std::cout<<ds.shm_perm.__key<<std::endl;
        }
    private:
        key_t _key;
        int _shmid;
        std::string _pathname ;
        int _proj_id;
        int _who;
        void *_addrshm;
};